package com.vben.system.biz.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vben.common.core.constant.CommonConstant;
import com.vben.common.exception.enums.ErrorCode;
import com.vben.common.exception.system.user.UserException;
import com.vben.system.api.dto.user.*;
import com.vben.system.api.entity.SysUser;
import com.vben.system.api.entity.SysUserLoginLog;
import com.vben.system.api.entity.SysUserRole;
import com.vben.system.api.vo.loginLog.SysUserLoginLogVO;
import com.vben.system.api.vo.user.SysUserVO;
import com.vben.system.biz.mapper.SysUserMapper;
import com.vben.system.biz.service.SysUserLoginLogService;
import com.vben.system.biz.service.SysUserRoleService;
import com.vben.system.biz.service.SysUserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author sunn
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysUserLoginLogService sysUserLoginLogService;
    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Override
    public Page<SysUser> pageVO(SysUserPageDTO param) {
        String username = param.getUsername();
        String name = param.getName();
        List<Long> userIds = param.getUserIds();
        String phone = param.getPhone();

        Page<SysUser> page = param.buildMpPage();
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(username), SysUser::getUsername, username);
        lambdaQueryWrapper.like(StrUtil.isNotBlank(name), SysUser::getName, name);
        lambdaQueryWrapper.in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds);
        lambdaQueryWrapper.like(StrUtil.isNotBlank(phone), SysUser::getPhone, phone);
        return page(page, lambdaQueryWrapper);
    }

    @Override
    public SysUserVO getLoginUserInfo() {
        long loginUserId = StpUtil.getLoginIdAsLong();
        SysUser sysUser = getById(loginUserId);
        return toVO(sysUser);
    }

    @Override
    public SysUserVO detail(Long userId) {
        if (userId == null) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户id为空");
        }
        SysUser sysUser = this.lambdaQuery().eq(SysUser::getUserId, userId).one();
        return toVO(sysUser);
    }

    @Override
    public SysUser getUserByUsername(String username) {
        if (StrUtil.isBlankIfStr(username)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户名为空");
        }
        return this.lambdaQuery().eq(SysUser::getUsername, username).one();
    }

    @Override
    public SysUser getUserByPhone(String phone) {
        if (StrUtil.isBlankIfStr(phone)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "手机号为空");
        }
        return this.lambdaQuery().eq(SysUser::getPhone, phone).one();
    }

    @Override
    public List<String> getUserPermissionList(Long userId) {
        return sysUserMapper.getUserPermissionList(userId);
    }

    @Override
    public List<String> getUserRoleList(Long userId) {
        return sysUserMapper.getUserRoleList(userId);
    }

    @Override
    public List<String> getUserRoleNameList(long loginUserId) {
        return sysUserMapper.getUserRoleNameList(loginUserId);
    }

    @Override
    public List<SysUserLoginLogVO> getOnlineDevice() {
        long loginUserId = StpUtil.getLoginIdAsLong();
        List<SysUserLoginLog> list = sysUserLoginLogService.lambdaQuery()
                .eq(SysUserLoginLog::getUserId, loginUserId)
                .eq(SysUserLoginLog::getLogoutFlag, CommonConstant.COMMON_NO)
                .list();
        return list.stream().map(log -> BeanUtil.copyProperties(log, SysUserLoginLogVO.class)).toList();
    }

    @Override
    public Long addUser(SysUser user) {
        String password = user.getPassword();
        if (StrUtil.isBlankIfStr(password)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "密码为空");
        }
        // 手机号校验
        Long phoneVerified = this.lambdaQuery().eq(StrUtil.isNotBlank(user.getPhone()), SysUser::getPhone, user.getPhone()).count();
        if (phoneVerified > 0) {
            throw new UserException(ErrorCode.INTERNAL_ERROR, "手机号" + user.getPhone() + "已存在");
        }

        // spring 内置加密方法，内部会生成随机盐值
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodePassword = encoder.encode(password);
        user.setPassword(encodePassword);
        boolean save = save(user);
        if (save) {
            return user.getUserId();
        } else {
            throw new UserException(ErrorCode.INTERNAL_ERROR);
        }
    }

    @Override
    public Boolean updateLoginUserInfo(SysUser user) {
        long loginUserId = StpUtil.getLoginIdAsLong();
        user.setUserId(loginUserId);
        return updateById(user);
    }

    @Override
    public Boolean updatePassword(SysUserUpdatePasswordDTO updatePasswordDTO) {
        String password = updatePasswordDTO.getPassword();
        String newPassword = updatePasswordDTO.getNewPassword();
        String confirmPassword = updatePasswordDTO.getConfirmPassword();

        if (StrUtil.isBlankIfStr(password) || StrUtil.isBlankIfStr(newPassword) || StrUtil.isBlankIfStr(confirmPassword)) {
            throw new UserException(ErrorCode.PARAM_INVALID);
        }

        long loginUserId = StpUtil.getLoginIdAsLong();
        SysUser sysUser = getById(loginUserId);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        boolean matches = encoder.matches(password, sysUser.getPassword());
        if (!matches) {
            throw new UserException(ErrorCode.PARAM_INVALID, "旧密码错误");
        }
        if (!StrUtil.equals(newPassword, confirmPassword)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "确认密码与新密码不一致");
        }
        String encodeNewPassword = encoder.encode(newPassword);
        sysUser.setPassword(encodeNewPassword);
        return updateById(sysUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPassword(SysUserResetPasswordDTO resetPasswordDTO) {
        List<Long> userIds = resetPasswordDTO.getUserIds();
        if (CollUtil.isEmpty(userIds)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户id为空");
        }

        List<SysUser> sysUsers = listByIds(userIds);
        if (CollUtil.isEmpty(sysUsers)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户不存在");
        }

        sysUsers.forEach(user -> {
            String password;

            if (StrUtil.isBlankIfStr(user.getUsername())) {
                password = CommonConstant.DEFAULT_PASSWORD;
            } else {
                password = user.getUsername();
            }

            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            String encodePassword = encoder.encode(password);
            user.setPassword(encodePassword);
        });

        return updateBatchById(sysUsers);
    }

    @Override
    @Transactional
    public Boolean kickoutByLoginId(KickoutDTO dto) {
        String loginId = dto.getLoginId();
        if (StrUtil.isBlankIfStr(loginId)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "loginId为空");
        }

        //更新登陆日志
        SysUserLoginLog loginLog = sysUserLoginLogService.getByLoginId(loginId);
        loginLog.setLogoutFlag(CommonConstant.COMMON_YSE);
        loginLog.setLogoutTime(LocalDateTime.now());
        boolean result = sysUserLoginLogService.updateById(loginLog);
        if (result) {
            StpUtil.kickout(loginLog.getUserId(), loginId);
        }
        return result;
    }

    @Override
    @Transactional
    public Boolean locked(SysUserLockedDTO sysUserLockedDTO) {
        List<Long> userIds = sysUserLockedDTO.getUserIds();
        if (CollUtil.isEmpty(userIds)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户id为空");
        }
        List<SysUser> sysUsers = listByIds(userIds);
        if (CollUtil.isEmpty(sysUsers)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户不存在");
        }
        sysUsers.forEach(user -> user.setLockFlag(CommonConstant.STATUS_LOCK));
        return updateBatchById(sysUsers);
    }

    @Override
    @Transactional
    public Boolean unlocked(SysUserLockedDTO sysUserLockedDTO) {
        List<Long> userIds = sysUserLockedDTO.getUserIds();
        if (CollUtil.isEmpty(userIds)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户id为空");
        }
        List<SysUser> sysUsers = listByIds(userIds);
        if (CollUtil.isEmpty(sysUsers)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户不存在");
        }
        sysUsers.forEach(user -> user.setLockFlag(CommonConstant.STATUS_NORMAL));
        return updateBatchById(sysUsers);
    }

    @Override
    @Transactional
    public Boolean delete(SysUserDeleteDTO sysUserDeleteDTO) {
        List<Long> userIds = sysUserDeleteDTO.getUserIds();
        if (CollUtil.isEmpty(userIds)) {
            throw new UserException(ErrorCode.PARAM_INVALID, "用户id为空");
        }
        // 删除用户角色关联
        LambdaQueryWrapper<SysUserRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SysUserRole::getUserId, userIds);
        sysUserRoleService.remove(lambdaQueryWrapper);

        return removeByIds(userIds);
    }

    @Override
    public SysUserVO toVO(SysUser user) {
        SysUserVO sysUserVO = new SysUserVO();
        BeanUtil.copyProperties(user, sysUserVO);
        // 封装用户角色列表
        List<String> roles = getUserRoleList(user.getUserId());
        sysUserVO.setRoles(roles);
        // 封装角色名
        List<String> roleNames = getUserRoleNameList(user.getUserId());
        sysUserVO.setRoleNames(roleNames);
        return sysUserVO;
    }
}




